#include "lcd.h"
#include "spi_my.h"
#include "gpio.h"
#include "delay.h"
#include "oledfont.h"

#define OLED_RST_Clr()  Gpio_Lcd_ResetBits(1)//RES
#define OLED_RST_Set()  Gpio_Lcd_SetBits(1)

#define OLED_DC_Clr()   Gpio_Lcd_ResetBits(0)//DC
#define OLED_DC_Set()   Gpio_Lcd_SetBits(0)

#define OLED_BLK_Clr()  Gpio_Lcd_ResetBits(2)//BLK
#define OLED_BLK_Set()  Gpio_Lcd_SetBits(2)		

u32 BACK_COLOR = WHITE;   //背景色
	
/******************************************************************************
      函数说明：LCD串行数据写入函数
      入口数据：dat  要写入的串行数据
      返回值：  无
******************************************************************************/
void LCD_Writ_Bus(u8 dat)
{
	Lcd_Spi_Write_Byte(dat);
}


/******************************************************************************
      函数说明：LCD写入数据
      入口数据：dat 写入的数据
      返回值：  无
******************************************************************************/
void LCD_WR_DATA8(u8 dat)
{
	OLED_DC_Set();//写数据
	LCD_Writ_Bus(dat);
}


/******************************************************************************
      函数说明：LCD写入数据
      入口数据：dat 写入的数据
      返回值：  无
******************************************************************************/
void LCD_WR_DATA(u32 dat)
{
	OLED_DC_Set();//写数据
	LCD_Writ_Bus(dat >> 16);
	LCD_Writ_Bus(dat >> 8);
	LCD_Writ_Bus(dat);
}


/******************************************************************************
      函数说明：LCD写入命令
      入口数据：dat 写入的命令
      返回值：  无
******************************************************************************/
void LCD_WR_REG(u8 dat)
{
	OLED_DC_Clr();//写命令
	LCD_Writ_Bus(dat);
}

/******************************************************************************
      函数说明：设置起始和结束地址
      入口数据：x1,x2 设置列的起始和结束地址
                y1,y2 设置行的起始和结束地址
      返回值：  无
******************************************************************************/
void LCD_Address_Set(u16 x1, u16 y1, u16 x2, u16 y2)
{
	LCD_WR_REG(0x2a);//列地址设置
	LCD_WR_DATA8(x1 >> 8);
	LCD_WR_DATA8(x1);
	LCD_WR_DATA8(x2 >> 8);
	LCD_WR_DATA8(x2);
	LCD_WR_REG(0x2b);//行地址设置
	LCD_WR_DATA8(y1 >> 8);
	LCD_WR_DATA8(y1);
	LCD_WR_DATA8(y2 >> 8);
	LCD_WR_DATA8(y2);
	LCD_WR_REG(0x2c);//储存器写
}


/******************************************************************************
      函数说明：LCD初始化函数
      入口数据：无
      返回值：  无
******************************************************************************/
void Lcd_Init(void)
{
	OLED_RST_Clr();
	delay_ms(200);
	OLED_RST_Set();
	delay_ms(20);
	OLED_BLK_Set();

//************* Start Initial Sequence **********//
	LCD_WR_REG(0x11); //Exit Sleep
	delay_ms(60);
	LCD_WR_REG(0XF2);
	LCD_WR_DATA8(0x18);
	LCD_WR_DATA8(0xA3);
	LCD_WR_DATA8(0x12);
	LCD_WR_DATA8(0x02);
	LCD_WR_DATA8(0XB2);
	LCD_WR_DATA8(0x12);
	LCD_WR_DATA8(0xFF);
	LCD_WR_DATA8(0x10);
	LCD_WR_DATA8(0x00);
	LCD_WR_REG(0XF8);
	LCD_WR_DATA8(0x21);
	LCD_WR_DATA8(0x04);
	LCD_WR_REG(0X13);

	LCD_WR_REG(0x36);    // Memory Access Control
	if (USE_HORIZONTAL == 0)LCD_WR_DATA8(0x08);
	else if (USE_HORIZONTAL == 1)LCD_WR_DATA8(0xC8);
	else if (USE_HORIZONTAL == 2)LCD_WR_DATA8(0x78);
	else LCD_WR_DATA8(0xA8);

	LCD_WR_REG(0xB4);
	LCD_WR_DATA8(0x02);
	LCD_WR_REG(0xB6);
	LCD_WR_DATA8(0x02);
	LCD_WR_DATA8(0x22);
	LCD_WR_REG(0xC1);
	LCD_WR_DATA8(0x41);
	LCD_WR_REG(0xC5);
	LCD_WR_DATA8(0x00);
	LCD_WR_DATA8(0x18);



	LCD_WR_REG(0x3a);
	LCD_WR_DATA8(0x66);
	delay_ms(50);



	LCD_WR_REG(0xE0);
	LCD_WR_DATA8(0x0F);
	LCD_WR_DATA8(0x1F);
	LCD_WR_DATA8(0x1C);
	LCD_WR_DATA8(0x0C);
	LCD_WR_DATA8(0x0F);
	LCD_WR_DATA8(0x08);
	LCD_WR_DATA8(0x48);
	LCD_WR_DATA8(0x98);
	LCD_WR_DATA8(0x37);
	LCD_WR_DATA8(0x0A);
	LCD_WR_DATA8(0x13);
	LCD_WR_DATA8(0x04);
	LCD_WR_DATA8(0x11);
	LCD_WR_DATA8(0x0D);
	LCD_WR_DATA8(0x00);
	LCD_WR_REG(0xE1);
	LCD_WR_DATA8(0x0F);
	LCD_WR_DATA8(0x32);
	LCD_WR_DATA8(0x2E);
	LCD_WR_DATA8(0x0B);
	LCD_WR_DATA8(0x0D);
	LCD_WR_DATA8(0x05);
	LCD_WR_DATA8(0x47);
	LCD_WR_DATA8(0x75);
	LCD_WR_DATA8(0x37);
	LCD_WR_DATA8(0x06);
	LCD_WR_DATA8(0x10);
	LCD_WR_DATA8(0x03);
	LCD_WR_DATA8(0x24);
	LCD_WR_DATA8(0x20);
	LCD_WR_DATA8(0x00);
	LCD_WR_REG(0x11);
	delay_ms(120);
	LCD_WR_REG(0x29);
	LCD_WR_REG(0x2C);
}


/******************************************************************************
      函数说明：LCD清屏函数
      入口数据：无
      返回值：  无
******************************************************************************/
void LCD_Clear(u32 Color)
{
	u16 i, j;
	LCD_Address_Set(0, 0, LCD_W - 1, LCD_H - 1);
	for (i = 0; i < LCD_W; i++)
	{
		for (j = 0; j < LCD_H; j++)
		{
			LCD_WR_DATA(Color);
		}

	}
}


/******************************************************************************
      函数说明：LCD显示汉字
      入口数据：x,y   起始坐标
                index 汉字的序号
                size  字号
      返回值：  无
******************************************************************************/
void LCD_ShowChinese32x32(u16 x, u16 y, u8 index, u8 size, u16 color)
{
	u8 i, j;
	u8 *temp, size1;
	if (size == 16) {temp = Hzk16;} //选择字号
	if (size == 32) {temp = Hzk32;}
	LCD_Address_Set(x, y, x + size - 1, y + size - 1); //设置一个汉字的区域
	size1 = size * size / 8; //一个汉字所占的字节
	temp += index * size1; //写入的起始位置
	for (j = 0; j < size1; j++)
	{
		for (i = 0; i < 8; i++)
		{
			if ((*temp & (1 << i)) != 0) //从数据的低位开始读
			{
				LCD_WR_DATA(color);//点亮
			}
			else
			{
				LCD_WR_DATA(BACK_COLOR);//不点亮
			}
		}
		temp++;
	}
}


/******************************************************************************
      函数说明：LCD显示汉字
      入口数据：x,y   起始坐标
      返回值：  无
******************************************************************************/
void LCD_DrawPoint(u16 x, u16 y, u16 color)
{
	LCD_Address_Set(x, y, x, y); //设置光标位置
	LCD_WR_DATA(color);
}


/******************************************************************************
      函数说明：在指定区域填充颜色
      入口数据：xsta,ysta   起始坐标
                xend,yend   终止坐标
      返回值：  无
******************************************************************************/
void LCD_Fill(u16 xsta, u16 ysta, u16 xend, u16 yend, u16 color)
{
	u16 i, j;
	LCD_Address_Set(xsta, ysta, xend, yend);   //设置光标位置
	for (i = ysta; i <= yend; i++)
	{
		for (j = xsta; j <= xend; j++)LCD_WR_DATA(color); //设置光标位置
	}
}


/******************************************************************************
      函数说明：LCD画一个大的点
      入口数据：x,y   起始坐标
      返回值：  无
******************************************************************************/
void LCD_DrawPoint_big(u16 x, u16 y, u16 color)
{
	LCD_Fill(x - 1, y - 1, x + 1, y + 1, color);
}


/******************************************************************************
      函数说明：画线
      入口数据：x1,y1   起始坐标
                x2,y2   终止坐标
      返回值：  无
******************************************************************************/
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2, u16 color)
{
	u16 t;
	int xerr = 0, yerr = 0, delta_x, delta_y, distance;
	int incx, incy, uRow, uCol;
	delta_x = x2 - x1; //计算坐标增量
	delta_y = y2 - y1;
	uRow = x1; //画线起点坐标
	uCol = y1;
	if (delta_x > 0)incx = 1; //设置单步方向
	else if (delta_x == 0)incx = 0; //垂直线
	else {incx = -1; delta_x = -delta_x;}
	if (delta_y > 0)incy = 1;
	else if (delta_y == 0)incy = 0; //水平线
	else {incy = -1; delta_y = -delta_x;}
	if (delta_x > delta_y)distance = delta_x; //选取基本增量坐标轴
	else distance = delta_y;
	for (t = 0; t < distance + 1; t++)
	{
		LCD_DrawPoint(uRow, uCol, color); //画点
		xerr += delta_x;
		yerr += delta_y;
		if (xerr > distance)
		{
			xerr -= distance;
			uRow += incx;
		}
		if (yerr > distance)
		{
			yerr -= distance;
			uCol += incy;
		}
	}
}


/******************************************************************************
      函数说明：画矩形
      入口数据：x1,y1   起始坐标
                x2,y2   终止坐标
      返回值：  无
******************************************************************************/
void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2, u16 color)
{
	LCD_DrawLine(x1, y1, x2, y1, color);
	LCD_DrawLine(x1, y1, x1, y2, color);
	LCD_DrawLine(x1, y2, x2, y2, color);
	LCD_DrawLine(x2, y1, x2, y2, color);
}


/******************************************************************************
      函数说明：画圆
      入口数据：x0,y0   圆心坐标
                r       半径
      返回值：  无
******************************************************************************/
void Draw_Circle(u16 x0, u16 y0, u8 r, u16 color)
{
	int a, b;
	// int di;
	a = 0; b = r;
	while (a <= b)
	{
		LCD_DrawPoint(x0 - b, y0 - a, color);       //3
		LCD_DrawPoint(x0 + b, y0 - a, color);       //0
		LCD_DrawPoint(x0 - a, y0 + b, color);       //1
		LCD_DrawPoint(x0 - a, y0 - b, color);       //2
		LCD_DrawPoint(x0 + b, y0 + a, color);       //4
		LCD_DrawPoint(x0 + a, y0 - b, color);       //5
		LCD_DrawPoint(x0 + a, y0 + b, color);       //6
		LCD_DrawPoint(x0 - b, y0 + a, color);       //7
		a++;
		if ((a * a + b * b) > (r * r)) //判断要画的点是否过远
		{
			b--;
		}
	}
}


/******************************************************************************
      函数说明：显示字符
      入口数据：x,y    起点坐标
                num    要显示的字符
                mode   1叠加方式  0非叠加方式
      返回值：  无
******************************************************************************/
void LCD_ShowChar(u16 x, u16 y, u8 num, u8 mode, u32 color)
{
	u8 temp;
	u8 pos, t;
	u16 x0 = x;
	if (x > LCD_W - 16 || y > LCD_H - 16)return;	 //设置窗口
	num = num - ' '; //得到偏移后的值
	LCD_Address_Set(x, y, x + 8 - 1, y + 16 - 1); //设置光标位置
	if (!mode) //非叠加方式
	{
		for (pos = 0; pos < 16; pos++)
		{
			temp = asc2_1608[(u16)num * 16 + pos];		 //调用1608字体
			for (t = 0; t < 8; t++)
			{
				if (temp & 0x01)LCD_WR_DATA(color);
				else LCD_WR_DATA(BACK_COLOR);
				temp >>= 1;
				x++;
			}
			x = x0;
			y++;
		}
	} else//叠加方式
	{
		for (pos = 0; pos < 16; pos++)
		{
			temp = asc2_1608[(u16)num * 16 + pos];		 //调用1608字体
			for (t = 0; t < 8; t++)
			{
				if (temp & 0x01)LCD_DrawPoint(x + t, y + pos, color); //画一个点
				temp >>= 1;
			}
		}
	}
}


/******************************************************************************
      函数说明：显示字符串
      入口数据：x,y    起点坐标
                *p     字符串起始地址
      返回值：  无
******************************************************************************/
void LCD_ShowString(u16 x, u16 y, const u8 *p, u16 color)
{
	while (*p != '\0')
	{
		if (x > LCD_W - 16) {x = 0; y += 16;}
		if (y > LCD_H - 16) {y = x = 0; LCD_Clear(RED);}
		LCD_ShowChar(x, y, *p, 0, color);
		x += 8;
		p++;
	}
}


/******************************************************************************
      函数说明：显示数字
      入口数据：m底数，n指数
      返回值：  无
******************************************************************************/
u32 mypow(u8 m, u8 n)
{
	u32 result = 1;
	while (n--)result *= m;
	return result;
}


/******************************************************************************
      函数说明：显示数字
      入口数据：x,y    起点坐标
                num    要显示的数字
                len    要显示的数字个数
      返回值：  无
******************************************************************************/
void LCD_ShowNum(u16 x, u16 y, u16 num, u8 len, u16 color)
{
	u8 t, temp;
	u8 enshow = 0;
	for (t = 0; t < len; t++)
	{
		temp = (num / mypow(10, len - t - 1)) % 10;
		if (enshow == 0 && t < (len - 1))
		{
			if (temp == 0)
			{
				LCD_ShowChar(x + 8 * t, y, ' ', 0, color);
				continue;
			} else enshow = 1;

		}
		LCD_ShowChar(x + 8 * t, y, temp + 48, 0, color);
	}
}


/******************************************************************************
      函数说明：显示小数
      入口数据：x,y    起点坐标
                num    要显示的小数
                len    要显示的数字个数
      返回值：  无
******************************************************************************/
void LCD_ShowNum1(u16 x, u16 y, float num, u8 len, u32 color)
{
	u8 t, temp;
	// u8 enshow = 0;
	u16 num1;
	num1 = num * 100;
	for (t = 0; t < len; t++)
	{
		temp = (num1 / mypow(10, len - t - 1)) % 10;
		if (t == (len - 2))
		{
			LCD_ShowChar(x + 8 * (len - 2), y, '.', 0, color);
			t++;
			len += 1;
		}
		LCD_ShowChar(x + 8 * t, y, temp + 48, 0, color);
	}
}


/******************************************************************************
      函数说明：显示40x40图片
      入口数据：x,y    起点坐标
      返回值：  无
******************************************************************************/
// void LCD_ShowPicture(u16 x1, u16 y1, u16 x2, u16 y2)
// {
// 	int i;
// 	LCD_Address_Set(x1, y1, x2, y2);
// 	for (i = 0; i < 1600; i++)
// 	{
// 		LCD_WR_DATA8(image[i * 3 + 2]);
// 		LCD_WR_DATA8(image[i * 3 + 1]);
// 		LCD_WR_DATA8(image[i * 3]);
// 	}
// }